home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 April / EnigmA AMIGA RUN 17 (1997)(G.R. Edizioni)(IT)[!][issue 1997-04][EAR-CD].iso / EARCD / text / hyper / hsc_source.lha / hsc / source / hsclib / tag_if.c < prev    next >
C/C++ Source or Header  |  1996-10-13  |  18KB  |  721 lines

  1. /*
  2.  * hsclib/tag_if.c
  3.  *
  4.  * tag callbacks for <$if>,<$else> and <$elseif>
  5.  *
  6.  * Copyright (C) 1996  Thomas Aglassinger
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  *
  22.  * updated: 18-Aug-1996
  23.  * created:  7-Oct-1995
  24.  */
  25.  
  26. #include "hsclib/inc_tagcb.h"
  27.  
  28. #include "hsclib/eval.h"
  29. #include "hsclib/parse.h"
  30. #include "hsclib/skip.h"
  31.  
  32. /* states for skip_if */
  33. #define IFST_TEXT    0          /* inside text */
  34. #define IFST_LT      1          /* after "<" */
  35. #define IFST_HSC     2          /* after "<$" */
  36. #define IFST_SLASH   3          /* after "</" */
  37. #define IFST_SLHSC   4          /* after "</$" */
  38. #define IFST_IF      5          /* after "<$IF" */
  39. #define IFST_ELSE    6          /* after "<$ELSE" */
  40. #define IFST_CIF     7          /* after "</$IF" */
  41. #define IFST_ELSEIF  8          /* after "<$ELSEIF" */
  42. #define IFST_TAG     9          /* inside a tag */
  43. #define IFST_ERR    99          /* error occured */
  44.  
  45. /* chars that represent TRUE, FALSE and
  46.  * UNDEF (error in if-expression) on if_stack
  47.  */
  48. #define ISTK_FALSE '0'          /* condition false */
  49. #define ISTK_TRUE  '1'          /* condition true */
  50. #define ISTK_UNDEF 'x'          /* condition unknown */
  51. #define ISTK_ELSE  'e'          /* after else */
  52.  
  53. typedef BYTE if_t;
  54.  
  55. /* error message */
  56. static VOID message_unma_else(HSCPRC * hp, HSCTAG * tag)
  57. {
  58.     hsc_message(hp, MSG_UNMA_ELSE,
  59.                 "unmatched %T", tag);
  60. }
  61.  
  62. /* forward references */
  63. BOOL handle_hsc_else(HSCPRC * hp, HSCTAG * tag);
  64. BOOL handle_hsc_elseif(HSCPRC * hp, HSCTAG * tag);
  65. BOOL handle_hsc_cif(HSCPRC * hp, HSCTAG * tag);
  66.  
  67. /* convert boolean value to value for if-stack */
  68. static if_t bool2ift(BOOL bval)
  69. {
  70.     if (bval)
  71.         return (ISTK_TRUE);
  72.     else
  73.         return (ISTK_FALSE);
  74. }
  75.  
  76. /*
  77.  *-------------------------------------
  78.  * IF-stack manipulation
  79.  *-------------------------------------
  80.  */
  81.  
  82. /* is_push: add a new value to the if-stack */
  83. static VOID is_push(HSCPRC * hp, if_t value)
  84. {
  85.     app_estrch(hp->if_stack, (char) value);
  86.  
  87.     DIF(fprintf(stderr, DHL "push IF-stack: \"%s\"\n", estr2str(hp->if_stack)));
  88. }
  89.  
  90. /* is_get: get first value from the if-stack */
  91. static if_t is_get(HSCPRC * hp)
  92. {
  93.     if_t value = ISTK_FALSE;
  94.  
  95.     if (hp->if_stack)
  96.     {
  97.         STRPTR stkstr = estr2str(hp->if_stack);
  98.  
  99.         DIF(fprintf(stderr, DHL "get  IF-stack: \"%s\"\n", stkstr));
  100.  
  101.         if (stkstr && (stkstr[0]))
  102.         {
  103.             char lastch = stkstr[strlen(stkstr) - 1];
  104.             if ((lastch != ISTK_TRUE)
  105.                 && (lastch != ISTK_FALSE)
  106.                 && (lastch != ISTK_ELSE))
  107.             {
  108.                 DIF(panic("Illegal value on if_stack"));
  109.             }
  110.             else
  111.                 value = (if_t) lastch;
  112.         }
  113.         else
  114.         {
  115.             DIF(panic("if_stack EMPTY"));
  116.         }
  117.     }
  118.     else
  119.     {
  120.         DIF(panic("if_stack UNDEFINED"));
  121.     }
  122.  
  123.     DIF(fprintf(stderr, DHL "get  IF-stack: value=`%c'\n", (char) value));
  124.  
  125.     return (value);
  126.  
  127. }
  128.  
  129. /* is_pop: remove first value of the if-stack */
  130. static if_t is_pop(HSCPRC * hp)
  131. {
  132.     if_t value = is_get(hp);
  133.  
  134.     if (!strlen(estr2str(hp->if_stack)))
  135.     {
  136.         DIF(panic("Popping empty if_stack"));
  137.     }
  138.  
  139.     get_left_estr(hp->if_stack, hp->if_stack, strlen(estr2str(hp->if_stack)) - 1);
  140.  
  141.     DIF(fprintf(stderr, DHL "pop  IF-stack: \"%s\"\n", estr2str(hp->if_stack)));
  142.  
  143.     return (value);
  144. }
  145.  
  146. /* is_empty: check if if-stack is empty */
  147. static BOOL is_empty(HSCPRC * hp)
  148. {
  149.     BOOL result = FALSE;
  150.  
  151.     if (!strlen(estr2str(hp->if_stack)))
  152.         result = TRUE;
  153.  
  154.     return (result);
  155. }
  156.  
  157. /*
  158.  *-------------------------------------
  159.  * SELECT-stack manipulation
  160.  *-------------------------------------
  161.  */
  162.  
  163. /*
  164.  * del_select_stack_node
  165.  */
  166. VOID del_select_stack_node(APTR data)
  167. {
  168.     STRPTR s = (STRPTR) data;
  169.     ufreestr(s);
  170. }
  171.  
  172. /*
  173.  * new_select_stack_node
  174.  */
  175. STRPTR new_select_stack_node(STRPTR data)
  176. {
  177.     return (strclone(data));
  178. }
  179.  
  180. /*
  181.  * cmp_select_stack_node
  182.  */
  183. int cmp_select_stack_node(APTR cmp_data, APTR lst_data)
  184. {
  185.     STRPTR s1 = (STRPTR) cmp_data;
  186.     STRPTR s2 = (STRPTR) lst_data;
  187.  
  188. #if DEBUG
  189.     if (!cmp_data)
  190.         panic("cmp_data = NULL");
  191.     if (!lst_data)
  192.         panic("lst_data = NULL");
  193. #endif
  194.  
  195.     if (!strcmp(s1, s2))
  196.         return (-1);
  197.     else
  198.         return (0);
  199. }
  200.  
  201. /* ss_push: add a new value to the if-stack */
  202. static VOID ss_push(HSCPRC * hp, STRPTR value)
  203. {
  204.     app_dlnode(hp->select_stack, new_select_stack_node(value));
  205.     DIF(fprintf(stderr, DHL "push select_stack: \"%s\"\n", value));
  206. }
  207.  
  208. /* ss_get: get first value from the select-stack */
  209. static STRPTR ss_get(HSCPRC * hp, EXPSTR * dest)
  210. {
  211.     STRPTR value = NULL;
  212.  
  213.     if (hp->select_stack)
  214.     {
  215.         DLNODE *nd = dll_first(hp->select_stack);
  216.  
  217.         if (nd)
  218.         {
  219.             value = dln_data(nd);
  220.         }
  221.         else
  222.         {
  223.             DIF(panic("select_stack EMPTY"));
  224.         }
  225.     }
  226.     else
  227.     {
  228.         DIF(panic("select_stack UNDEFINED"));
  229.     }
  230.  
  231.     DIF(
  232.            if (value)
  233.            fprintf(stderr, DHL "get  select_stack: value=`%s'\n", value)
  234.         );
  235.  
  236.     return (value);
  237. }
  238.  
  239. /* ss_pop: remove first value of select-stack */
  240. static STRPTR ss_pop(HSCPRC * hp, EXPSTR * dest)
  241. {
  242.     STRPTR value = ss_get(hp, dest);
  243.  
  244.     if (!value)
  245.     {
  246.         DIF(panic("popping empty select_stack"));
  247.         value = "";
  248.     }
  249.  
  250.     DIF(fprintf(stderr, DHL "pop  select_stack: \"%s\"\n", value));
  251.  
  252.     return (value);
  253. }
  254.  
  255. /* ss_empty: check if if-stack is empty */
  256. static BOOL ss_empty(HSCPRC * hp)
  257. {
  258.     BOOL result = FALSE;
  259.  
  260.     if (dll_first(hp->select_stack))
  261.         result = TRUE;
  262.  
  263.     return (result);
  264. }
  265.  
  266. /*
  267.  *-------------------------------------
  268.  * misc. functions
  269.  *-------------------------------------
  270.  */
  271.  
  272. /*
  273.  * remove_cif_tag
  274.  *
  275.  * remove </$IF> from closing tag stack
  276.  */
  277. static VOID remove_cif_tag(HSCPRC * hp)
  278. {
  279.     HSCTAG ciftag;              /* artificial if-tag to remove */
  280.  
  281.     ciftag.name = HSC_IF_STR;
  282.     remove_ctag(hp, &ciftag);   /* remove closing tag from stack */
  283.     DIF(fprintf(stderr, DHL "</$IF> removed\n"));
  284. }
  285.  
  286. /*
  287.  * get_condition
  288.  *
  289.  * evaluate if-condition
  290.  */
  291. static if_t get_condition(HSCPRC * hp)
  292. {
  293.     if_t cond = ISTK_UNDEF;     /* boolean result of expression */
  294.     STRPTR condstr = NULL;
  295.     STRPTR nw = infgetw(hp->inpf);
  296.  
  297.     if (nw)
  298.     {
  299.         /* create temp. attr */
  300.         HSCVAR *condattr = new_hscattr(PREFIX_TMPATTR "if.condition");
  301.  
  302.         /* skip `COND=' if there (new syntax) */
  303.         if (!upstrcmp(nw, CONDITION_ATTR))
  304.             parse_eq(hp);
  305.         else
  306.             inungetcw(hp->inpf);
  307.  
  308.         condattr->vartype = VT_BOOL;
  309.  
  310.         condstr = eval_expression(hp, condattr, NULL);
  311.  
  312.         /* check for closing ">" */
  313.         parse_gt(hp);
  314.  
  315.         if (condstr)
  316.             if (get_varbool(condattr))
  317.                 cond = ISTK_TRUE;
  318.             else
  319.                 cond = ISTK_FALSE;
  320.         else
  321.             cond = ISTK_UNDEF;
  322.  
  323.         /* remove temp. attribute */
  324.         del_hscattr(condattr);
  325.     }
  326.     return (cond);
  327. }
  328.  
  329. /*
  330.  *-------------------------------------
  331.  * skip_if: the ultimate if-handler
  332.  *-------------------------------------
  333.  */
  334.  
  335. /*
  336.  * skip_if
  337.  *
  338.  * skip text, until <$/IF> or <$ELSE> is found
  339.  * also handle recursive IFs
  340.  *
  341.  * params: inpf..input file
  342.  * result: IFST_CIF, if exited with </$IF>,
  343.  *         IFST_ELSE, if exited with </$ELSE>
  344.  * errors: call err_eof(), if end-of-file,
  345.  *         return IFST_ERR
  346.  */
  347.  
  348. static BYTE skip_if(HSCPRC * hp)
  349. {
  350.     INFILE *inpf = hp->inpf;
  351.     BOOL quit = FALSE;          /* TRUE, if end-of-if found */
  352.     STRPTR nw = NULL;           /* word read from input */
  353.     BYTE state = IFST_TEXT;     /* current state */
  354.     LONG if_nest = 0;           /* counter for $IF nesting */
  355.  
  356.     do
  357.     {
  358.         if (state != IFST_TAG)
  359.             nw = infgetw(inpf);
  360.         if (nw)
  361.         {
  362.             if (state == IFST_TAG)
  363.             {
  364.                 /*
  365.                  * skip inside tags
  366.                  */
  367.                 BYTE tag_state = TGST_TAG;      /* state var passe to */
  368.                 /*     eot_reached() */
  369.  
  370.                 do
  371.                 {
  372.                     if (eot_reached(hp, &tag_state))    /* CHECK: empty body? */
  373.                         state = IFST_TEXT;
  374.                 }
  375.                 while ((tag_state != TGST_END) && !(hp->fatal));
  376.             }
  377.             else
  378.             {
  379.                 /*
  380.                  * NOTE: I know that this section could be
  381.                  * shorter, but it would also make the
  382.                  * source less readable
  383.                  */
  384.  
  385.                 /*
  386.                  * evaluate next state depending on
  387.                  * previous state
  388.                  */
  389.                 switch (state)
  390.                 {
  391.  
  392.                 case IFST_TEXT:
  393.                     if (!strcmp(nw, "<"))
  394.                         state = IFST_LT;
  395.                     break;
  396.  
  397.                 case IFST_LT:
  398.                     if (!strcmp(nw, "$"))
  399.                         state = IFST_HSC;
  400.                     else if (!strcmp(nw, "/"))
  401.                         state = IFST_SLASH;
  402.                     else if (!upstrcmp(nw, HSC_COMMENT_STR))
  403.                     {
  404.  
  405.                         skip_hsc_comment(hp);
  406.                         state = IFST_TEXT;
  407.                     }
  408.                     else
  409.                         state = IFST_TAG;
  410.  
  411.                     break;
  412.  
  413.                 case IFST_HSC:
  414.                     if (!upstrcmp(nw, "ELSE"))
  415.                         state = IFST_ELSE;
  416.                     else if (!upstrcmp(nw, "IF"))
  417.                         state = IFST_IF;
  418.                     else if (!upstrcmp(nw, "ELSEIF"))
  419.                         state = IFST_IF;
  420.                     else
  421.                         state = IFST_TAG;
  422.                     break;
  423.  
  424.                 case IFST_SLASH:
  425.                     if (!strcmp(nw, "$"))
  426.                         state = IFST_SLHSC;
  427.                     else
  428.                         state = IFST_TAG;
  429.  
  430.                     break;
  431.  
  432.                 case IFST_SLHSC:
  433.                     if (!upstrcmp(nw, "IF"))
  434.                         state = IFST_CIF;
  435.                     else
  436.                         state = IFST_TAG;
  437.  
  438.                     break;
  439.                 }
  440.  
  441.                 /*
  442.                  * handle special states
  443.                  */
  444.                 switch (state)
  445.                 {
  446.  
  447.                 case IFST_IF:
  448.                     state = IFST_TAG;
  449.                     if_nest++;
  450.                     DIF(fprintf(stderr, DHL "skip <$IF>   (%ld)\n", if_nest));
  451.                     break;
  452.  
  453.                 case IFST_ELSE:
  454.                     if (if_nest)
  455.                     {
  456.                         state = IFST_TAG;
  457.                         DIF(fprintf(stderr, DHL "skip <$ELSE> (%ld)\n", if_nest));
  458.                     }
  459.                     else
  460.                     {
  461.                         /* TODO: check for 2nd <$ELSE> */
  462.                         quit = TRUE;
  463.                     }
  464.  
  465.                     break;
  466.  
  467.                 case IFST_ELSEIF:
  468.                     if (if_nest)
  469.                     {
  470.                         state = IFST_TAG;
  471.                         DIF(fprintf(stderr, DHL "skip <$ELSEIF> (%ld)\n", if_nest));
  472.                     }
  473.                     else
  474.                     {
  475.                         /* TODO: check for 2nd <$ELSE> */
  476.                         quit = TRUE;
  477.                     }
  478.  
  479.                     break;
  480.  
  481.                 case IFST_CIF:
  482.                     if (if_nest)
  483.                     {
  484.  
  485.                         state = IFST_TAG;
  486.                         if_nest--;
  487.                         DIF(fprintf(stderr, DHL "skip </$IF>  (%ld)\n", if_nest + 1));
  488.  
  489.                     }
  490.                     else
  491.                         quit = TRUE;
  492.  
  493.                     break;
  494.                 }
  495.             }
  496.         }
  497.         else
  498.         {
  499.             hsc_msg_eof(hp, "missing </" HSC_IF_STR ">");
  500.             state = IFST_ERR;
  501.         }
  502.     }
  503.     while (!quit && nw);
  504.  
  505.     /* check for legal end state */
  506.     if ((state == IFST_CIF)
  507.         || (state == IFST_ELSE))
  508.     {
  509.         parse_wd(hp, ">");
  510.  
  511.         if (state == IFST_CIF)
  512.         {
  513.             DIF(fprintf(stderr, DHL "</$IF> reached\n"));
  514.         }
  515.         else
  516.         {
  517.             DIF(fprintf(stderr, DHL "<$ELSE> reached\n"));
  518.         }
  519.     }
  520.     else if (state == IFST_ELSEIF)
  521.     {
  522.         DIF(fprintf(stderr, DHL "<$ELSEIF> reached\n"));
  523.     }
  524.  
  525.     return (state);
  526. }
  527.  
  528. static VOID skip_until_conditional(HSCPRC * hp)
  529. {
  530.     EXPSTR *s = init_estr(32);
  531.     skip_until_tag(hp, s, HSC_ELSE_STR "|" HSC_ELSEIF_STR, HSC_IF_STR);
  532.     del_estr(s);
  533. }
  534.  
  535. /*
  536.  *
  537.  * exported funcs
  538.  *
  539.  */
  540.  
  541. /*
  542.  *-------------------------------------
  543.  * <$IF> conditional conversion
  544.  *-------------------------------------
  545.  */
  546. BOOL handle_hsc_if(HSCPRC * hp, HSCTAG * tag)
  547. {
  548. #if 0
  549.     if_t new_cond = get_condition(hp);
  550.  
  551.     /* store new_cond on stack */
  552.     is_push(hp, new_cond);
  553.  
  554.     if (new_cond != ISTK_TRUE)
  555.     {
  556.         BYTE state;
  557.  
  558.         DIF(DMSG("IF: refused"));
  559.         state = skip_if(hp);
  560.         if ((state == IFST_ELSE) || (state == IFST_ELSEIF))
  561.         {
  562.             if (new_cond != ISTK_UNDEF)
  563.             {
  564.                 if (state == IFST_ELSE)
  565.                 {
  566.                     DIF(DMSG("IF: process ELSE"));
  567.                     handle_hsc_else(hp, find_strtag(hp->deftag, HSC_ELSE_STR));
  568.                 }
  569.                 else if (state == IFST_ELSEIF)
  570.                 {
  571.                     DIF(DMSG("IF: process ELSEIF"));
  572.                     handle_hsc_elseif(hp, find_strtag(hp->deftag, HSC_ELSE_STR));
  573.                 }
  574.                 else
  575.                 {
  576.                     DIF(panic("unexpected if-state"));
  577.                 }
  578.             }
  579.             else
  580.             {
  581.                 DIF(DMSG("ELSE/ELSEIF: refused (undef)"));
  582.                 state = skip_if(hp);
  583.                 if (state == IFST_ELSE)
  584.                     message_unma_else(hp, tag);
  585.                 remove_cif_tag(hp);
  586.             }
  587.         }
  588.         else if (state == IFST_CIF)
  589.             remove_cif_tag(hp);
  590.         else if (state != IFST_ERR)
  591.         {
  592.             D(panic("strange if-state"));
  593.         }
  594.     }
  595.     else
  596.     {
  597.         DIF(DMSG(" IF: GRANTED"));
  598.     }
  599. #else
  600. #ifdef OLDIFCOND
  601.     if_t new_cond = get_condition(hp);
  602. #else
  603.     BOOL new_condbool = get_varbool_byname(tag->attr, CONDITION_ATTR);
  604.     if_t new_cond = bool2ift(new_condbool);
  605. #endif
  606.  
  607.     /* store new_cond on stack */
  608.     is_push(hp, new_cond);
  609.     DIF(fprintf(stderr, DHL "  new_cond=`%c'\n", new_cond));
  610.  
  611.     if (new_cond != ISTK_TRUE)
  612.     {
  613.         DIF(DMSG("IF: refused"));
  614.         skip_until_conditional(hp);
  615.     }
  616.     else
  617.     {
  618.         DIF(DMSG(" IF: GRANTED"));
  619.     }
  620. #endif
  621.  
  622.     return (FALSE);
  623. }
  624.  
  625. /*
  626.  *-------------------------------------
  627.  * </$IF> conditional conversion
  628.  *-------------------------------------
  629.  */
  630. BOOL handle_hsc_cif(HSCPRC * hp, HSCTAG * tag)
  631. {
  632.     DIF(fprintf(stderr, DHL "IF: standard closing handler\n"));
  633.  
  634.     is_pop(hp);                 /* remove if-value from stack */
  635.  
  636.     return (FALSE);
  637. }
  638.  
  639. /*
  640.  *-------------------------------------
  641.  * <$ELSE> conditional conversion
  642.  *-------------------------------------
  643.  */
  644. BOOL handle_hsc_else(HSCPRC * hp, HSCTAG * tag)
  645. {
  646.     if (is_empty(hp))
  647.     {
  648.         panic("unhandled <$else>");
  649.     }
  650.     else
  651.     {
  652.         if_t value = is_pop(hp);
  653.  
  654.         if (value == ISTK_ELSE)
  655.         {
  656.             message_unma_else(hp, tag);
  657.         }
  658.         else if (value == ISTK_FALSE)
  659.         {
  660.             DIF(fprintf(stderr, DHL "ELSE: GRANTED\n"));
  661.         }
  662.         else
  663.         {
  664.             DIF(fprintf(stderr, DHL "ELSE: refused\n"));
  665.             skip_until_conditional(hp);
  666.         }
  667.  
  668.         /* mark <$else>-occured on if-stack */
  669.         is_push(hp, ISTK_ELSE);
  670.     }
  671.  
  672.     return (FALSE);
  673. }
  674.  
  675. /*
  676.  *-------------------------------------
  677.  * <$ELSEIF> conditional conversion
  678.  *-------------------------------------
  679.  */
  680. BOOL handle_hsc_elseif(HSCPRC * hp, HSCTAG * tag)
  681. {
  682.     BOOL new_condbool = get_varbool_byname(tag->attr, CONDITION_ATTR);
  683.     if_t new_cond = bool2ift(new_condbool);
  684.  
  685.     if (is_empty(hp))
  686.     {
  687.         message_unma_else(hp, tag);
  688.     }
  689.     else
  690.     {
  691.         if_t old_cond = is_pop(hp);     /* condition of previous if/elseif */
  692.         if_t push_cond = old_cond;      /* value to be pushed on stack */
  693.  
  694.         if (old_cond == ISTK_ELSE)
  695.         {
  696.             message_unma_else(hp, tag);
  697.         }
  698.         else if (old_cond == ISTK_TRUE)
  699.         {
  700.             DIF(fprintf(stderr, DHL "ELSEIF: refused (old_cond was true)\n"));
  701.             skip_until_conditional(hp);
  702.         }
  703.         else if (new_cond == ISTK_TRUE)
  704.         {
  705.             DIF(fprintf(stderr, DHL "ELSEIF: GRANTED\n"));
  706.             push_cond = new_cond;
  707.         }
  708.         else
  709.         {
  710.             DIF(fprintf(stderr, DHL "ELSEIF: refused (new_cond is false)\n"));
  711.             skip_until_conditional(hp);
  712.         }
  713.  
  714.         /* push new condition to if-stack */
  715.         is_push(hp, push_cond);
  716.     }
  717.  
  718.     return (FALSE);
  719. }
  720.  
  721.